/* uniformequallyspacedgenerator.h
 *
 *	Copyright (C) 2008 CRIMERE
 *	Copyright (C) 2008 Jean-Marc Mercier
 *	
 *	This file is part of OTS (optimally transported schemes), an open-source library
 *	dedicated to scientific computing. http://code.google.com/p/optimally-transported-schemes/
 *
 *	CRIMERE makes no representations about the suitability of this
 *	software for any purpose. It is provided "as is" without express or
 *	implied warranty.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 */
#include <src/miscellaneous/OS_basic.h>
#include <src/miscellaneous/Function_Utilities.h>
#include <src/algorithm/random/Generator_Facilities.h>
/*!
	A set of classes to define uniform equally spaced generator
*/
#if !defined(_UniformEquallySpacedGenerator_Base_)
#define _UniformEquallySpacedGenerator_Base_
namespace boost {
namespace random {
/*!
	given a vector of steps \f$[I_1,...,I_N],
	return a vector \f$\{x_{i_1},...,x_{i_N}\}_{i_1,...,i_N}\f$, \f$0 \le i_1 < I_1\f$, ...,\f$0 \le i_N < I_N\f$
	such that
\f[
	x_{i_j}=\frac{i+.5}{I_j}
\f]
*/
	template <class data, std::size_t Dim = OS_type_helper<data>::Dim>
class UniformEquallySpacedGenerator : public Generator_facilities<UniformEquallySpacedGenerator<data,Dim>>
 {
 public:
	typedef std::vector<std::size_t>	vector_size_type;
	typedef data						result_type;
	UniformEquallySpacedGenerator( const vector_size_type& size) : i_(Dim),size_(Dim), result_(Dim){
		std::fill(i_.begin(),i_.end(),0);
		std::copy(size.begin(),size.end(),size_.begin());
		for (OS_size i = 0; i < Dim; ++i)
			result_[i] = .5/ ( (double) (size_[i]) );
	};

	result_type operator()() // next sampling
	{
		result_[0] = (i_[0]+.5)/ ( (double) size_[0] );
		for (OS_size i = 0; i < Dim; ++i) {
			if (i_[i] >= size_[i]) {
				i_[i] = 0;
				++i_[i+1]; // should throw an exception if bounds are overruned
				result_[i] = (.5)/ ( (double) size_[i] );
				result_[i+1] = (i_[i+1]+.5)/ ( (double) size_[i+1] );
			}
			else {
				++i_[0];
				break;
			}
		};
		return result_;
	};
 private : 
	 vector_size_type size_;
	 vector_size_type i_;
	 result_type result_;
 };

template<>
class UniformEquallySpacedGenerator<OS_double,0> : 
	public Generator_facilities<UniformEquallySpacedGenerator<OS_double,0>>
{
 public:
	UniformEquallySpacedGenerator( OS_size step = 0, OS_size i = 0) : Steps_(step), i_(i) {}
	OS_double operator()() // next sampling
	{
		OS_DYNAMIC_CHECK(i_ >=0 && i_ < Steps_, "Uniform Equally Spaced Generator out of bounds");
		return ( (i_++)+.5)/Steps_;
	};
 private : 
	 OS_size Steps_;
	 OS_size i_;
 };

template <class data, std::size_t Dim = 0>
class UniformSegmentGenerator : public Generator_facilities<UniformSegmentGenerator<data,Dim>>
{
public :
	OS_STATIC_CHECK(false); //to implement
};

template <>
class UniformSegmentGenerator<OS_double,0> : public Generator_facilities<UniformSegmentGenerator<OS_double,0>>
 {
 public:
	typedef OS_double result_type;
	UniformSegmentGenerator( OS_size step = 1, OS_size i = 0) : Steps_(step), i_(i) {}
	OS_double operator()() // next sampling
	{
		OS_DYNAMIC_CHECK(i_ >= 0 && i_ <= Steps_, "Uniform Equally Spaced Generator out of bounds");
		return ( (OS_double) (i_++) )/Steps_;
	};
 private : 
	 OS_size Steps_;
	 OS_size i_;
 };
} //random
} //boost



#endif
